package com.example.qxfw.dysjrh.service.impl;

import com.dmgis.util.DateTime;
import com.example.qxfw.common.SysResult;
import com.example.qxfw.common.service.FileRequestService;
import com.example.qxfw.common.util.GetPath;
import com.example.qxfw.dysjrh.config.DmgisConfig;
import com.example.qxfw.dysjrh.entity.ContourSetting;
import com.example.qxfw.dysjrh.entity.GridData;
import com.example.qxfw.dysjrh.entity.NumData;
import com.example.qxfw.dysjrh.entity.QxGridFile;
import com.example.qxfw.dysjrh.entity.vo.GridVo;
import com.example.qxfw.dysjrh.entity.vo.NumericaVo;
import com.example.qxfw.dysjrh.mapper.MsgmediumsmallscaleMapper;
import com.example.qxfw.dysjrh.service.NumericaService;
import com.example.qxfw.dysjrh.utils.FileUtil;
import com.example.qxfw.dysjrh.utils.GridUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.ParseException;
import java.util.*;

@Slf4j
@Service
@RequiredArgsConstructor
public class NumericaServiceImpl implements NumericaService {

    private static final Logger logger = LoggerFactory.getLogger(GridServiceImpl.class);

    @Qualifier("mongoPrimaryTemplate")
    @Autowired
    private MongoTemplate mongoTemplate;

    private final GridUtil gridUtil;

    private final DmgisConfig dmgisConfig;

    private final FileUtil fileUtil;

    private final FileRequestService fileRequestService;

    //查询要素
    private static final Map<String, String> maps = new HashMap<>();

    static {
        maps.put("降水量", "TPE");
        maps.put("K指标", "KIDX");
        maps.put("SI指数", "SWID");
        maps.put("CAPE", "CAPE");
        maps.put("比湿", "SHU");
        maps.put("地面气压", "PRS");
        maps.put("海平面气压", "SSP");
        maps.put("500hPa温", "500T");
        maps.put("700hPa温", "700T");
        maps.put("850hPa温", "850T");
        maps.put("500hPa高", "500GPH");
        maps.put("700hPa高", "700GPH");
        maps.put("850hPa高", "850GPH");
        maps.put("500hPa风", "500uv.u");
        maps.put("700hPa风", "700uv.u");
        maps.put("850hPa风", "850uv.u");
        maps.put("500hPa湿", "500R");
        maps.put("700hPa湿", "700R");
        maps.put("850hPa湿", "850R");
        maps.put("500hPa垂直速度", "500VVM");
        maps.put("700hPa垂直速度", "700VVM");
        maps.put("850hPa垂直速度", "850VVM");
        maps.put("500hPa水汽通量", "500MOFU");
        maps.put("700hPa水汽通量", "700MOFU");
        maps.put("850hPa水汽通量", "850MOFU");
        maps.put("500hPa涡度", "500RVO");
        maps.put("700hPa涡度", "700RVO");
        maps.put("850hPa涡度", "850RVO");
        maps.put("500hPa水汽通里散度", "500MFVO");
        maps.put("700hPa水汽通里散度", "700MFVO");
        maps.put("850hPa水汽通里散度", "850MFVO");
    }

    @Override
    public Object getNumerica(NumData numData) {
        try {
            String type = maps.get(numData.getType());

            if (type == null) {
                throw new IllegalArgumentException("Invalid type: " + numData.getType());
            }

            //新疆区台表名
            String collectionName = null;
//            Query query = new Query();
//            //风速
//            if (type.contains("uv"))
//                query.addCriteria(Criteria.where("type").in(type + ".U", type + ".V"));
//            else {
//                //其他要素
//                query.addCriteria(Criteria.where("type").is(type));
//            }
//
//            query.addCriteria(Criteria.where("datechar").is(numData.getDateChar().toString()));//日期
//            query.addCriteria(Criteria.where("timechar").is(numData.getTimeChar()));//时刻
//
//
//            if (numData.getByTime() == 24) {
//                //取24h的数据
//                int nTimes = Integer.parseInt(numData.getNTimes());
//                //左值
//                String lTimes = null;
//                if (nTimes == 000){
//                     lTimes = String.format("%03d", nTimes);
//                }else {
//                    lTimes = String.format("%03d", nTimes - 24);
//                }
//                //右值
//                String hTimes = String.format("%03d", nTimes);
//                query.addCriteria(Criteria.where("ntimes").gte(lTimes).lte(hTimes));
//            } else {
//                //3小时的格点
//                query.addCriteria(Criteria.where("ntimes").is(numData.getNTimes()));
//            }
//
//            if ("EC".equals(numData.getNumberType())) {
//                collectionName = "grid_micaps_file";
//            } else {
//                collectionName = "grid_cmameso_file";
//            }
//
//
//            List<NumericaVo> numericaVos = mongoTemplate.find(query, NumericaVo.class, collectionName);

            List<NumericaVo>  numericaVos = new ArrayList<>();
            //查询本地mongo数据
            Map<String, Object> queryMap = new HashMap<String, Object>();
            int timeChange = 0;
            if(numData.getByTime() == 24) {
                timeChange = 21;
            }
            //取24h或3h的数据
            int nTimes = Integer.parseInt(numData.getNTimes());
            for(int i = nTimes - timeChange ; i <= nTimes; i+=3){
                String times = String.format("%03d", i);
                String collectionname = null;
                if ("EC".equals(numData.getNumberType())){
                    collectionname = "grid_micaps_file";
                }else {
                    collectionname = "grid_cmameso_file";
                }
                queryMap.put("collectionName", collectionname);
                queryMap.put("advCode","");
                queryMap.put("ntimes", times);
                queryMap.put("datechar",numData.getDateChar().toString());
                queryMap.put("timechar",numData.getTimeChar());
                queryMap.put("numberType",numData.getNumberType());

                //风速
                String[] windTypes =new String[0];
                if (type.contains("uv")){
                    if (type.contains("500uv.u")) {
                         windTypes =new String[] {"500uv.u", "500uv.v"};
                    }else if (type.contains("700uv.u")){
                         windTypes = new String[]{"700uv.u", "700uv.v"};
                    }else if (type.contains("850uv.u")){
                         windTypes =new String[] {"850uv.u", "850uv.v"};
                    }
                    for(String windType : windTypes){
                        queryMap.put("type", windType);
                        byte[] bytes = selectData1(queryMap);
                        NumericaVo numericaVo = new NumericaVo();
                        numericaVo.setData(bytes);
                        numericaVo.setNtimes(times);
                        numericaVo.setType(windType);
                        numericaVo.setDatechar(numData.getDateChar().toString());
                        numericaVo.setTimechar(numData.getTimeChar());
                        numericaVo.setDateyear(String.valueOf(numData.getDateChar().getYear()));
                        numericaVo.setNumberType(numData.getNumberType());
                        numericaVos.add(numericaVo);
//                        queryMap.clear();
                    }
                } //其他要素
                else {
                    queryMap.put("type", type);
                    byte[] bytes = fileRequestService.selectData(queryMap);
                    NumericaVo numericaVo = new NumericaVo();
                    numericaVo.setData(bytes);
                    numericaVo.setNtimes(times);
                    numericaVo.setType(type);
                    numericaVo.setDatechar(numData.getDateChar().toString());
                    numericaVo.setTimechar(numData.getTimeChar());
                    numericaVo.setDateyear(String.valueOf(numData.getDateChar().getYear()));
                    numericaVo.setNumberType(numData.getNumberType());
                    numericaVos.add(numericaVo);
                    queryMap.clear();
                }
            }

            if (!numericaVos.isEmpty()) {
//                String[] data = getData(dmgisConfig.getNumericaFilePath(), numericaVos);
                //风速风向
                if (type.contains("uv")) {
                    String[] winds = getWindGridData(dmgisConfig.getGridFilePath(), numericaVos);
                    if (winds.length != 0) {
                        return gridUtil.ReadWinGridFiles(winds);
                    }
                } else {
                    String[] gridFile = getGridData(dmgisConfig.getGridFilePath(), numericaVos);
                    if (gridFile.length > 0) {
                        return gridUtil.ReadGridFile(gridFile);
                    }
                }
            }
        } catch (ParseException e) {
            logger.error("Error occurred while fetching numgrid data", e);
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public List<QxGridFile> queryListByDateCharTimeCharNtimesType(NumData numData) {
        if(numData != null){
            String type = maps.get(numData.getType());
            if(type == null){
                throw new IllegalArgumentException("Invalid type: " + numData.getType());
            }
            //新疆区台表名
            String collectionName = null;
            List<QxGridFile>  listGridVo = new ArrayList<>();
            //查询本地mongo数据
            Map<String, Object> queryMap = new HashMap<String, Object>();
            if ("EC".equals(numData.getNumberType())){
                collectionName = "grid_micaps_file";
            }else {
                collectionName = "grid_cmameso_file";
            }
            queryMap.put("datechar",numData.getDateChar().toString());
            queryMap.put("timechar",numData.getTimeChar());
            queryMap.put("collectionName", collectionName);
            queryMap.put("advCode","");
            int timeChange = 0;
            if(numData.getByTime() == 24) {
                timeChange = 21;
            }

            //取24h或3h的数据
            int nTimes = Integer.parseInt(numData.getNTimes());
            for(int i = nTimes - timeChange ; i <= nTimes; i+=3){
                String times = String.format("%03d", i);
                queryMap.put("ntimes", times);
                //风速
                if (type.contains("uv")){

                    String[] windTypes =new String[0];
                    if (type.contains("uv")){
                        if (type.contains("500uv")) {
                            windTypes =new String[] {"500uv.u", "500uv.v"};
                        }else if (type.contains("700uv")){
                            windTypes = new String[]{"700uv.u", "700uv.v"};
                        }else if (type.contains("850uv")){
                            windTypes =new String[] {"850uv.u", "850uv.v"};
                        }
                    for(String windType : windTypes){
                        queryMap.put("type", windType);
                        byte[] bytes = selectData1(queryMap);
                        QxGridFile gridVo = new QxGridFile();
                        gridVo.setData(bytes);
                        gridVo.setNtimes(times);
                        gridVo.setType(windType);
                        gridVo.setDatechar(numData.getDateChar().toString());
                        gridVo.setTimechar(numData.getTimeChar());

                        System.out.println(gridVo);
                        listGridVo.add(gridVo);
//                        queryMap.clear();
                    }
                    }
                }
                //其他要素
                else {
                    queryMap.put("type", type);
                    byte[] bytes = fileRequestService.selectData(queryMap);
                    QxGridFile gridVo = new QxGridFile();
                    gridVo.setData(bytes);
                    gridVo.setNtimes(times);
                    gridVo.setType(type);
                    gridVo.setDatechar(numData.getDateChar().toString());
                    gridVo.setTimechar(numData.getTimeChar());
                    listGridVo.add(gridVo);
                    queryMap.clear();
                }
                return listGridVo;
            }
        }
        return null;
    }

    private final MsgmediumsmallscaleMapper msgmediumsmallscaleMapper;

    @Override
    public List<ContourSetting> getContourSetting(String paramtype) {
        return msgmediumsmallscaleMapper.getContourSetting(paramtype);
    }

    public byte[] selectData1(Map<String, Object> queryMap) {
        String dbName = dmgisConfig.getDbname();
        String collectionName = (String)queryMap.get("collectionName");
//        queryMap.remove("collectionName");
//        if (!StringUtil.IsNullOrEmpty((String)queryMap.get("advCode"))) {
        String advCode = (String)queryMap.get("advCode");
        if (Objects.nonNull(advCode) && !advCode.isEmpty()) {
            dbName = dbName + "_" + queryMap.get("advCode");
            queryMap.remove("advCode");
        }

        byte[] result = null;
        String basePath = GettqFilepath();
        String filePath = basePath + File.separator +  "DmgisPubData" + File.separator + dbName + File.separator + collectionName + File.separator;
        filePath = GetPath.action(queryMap, filePath, collectionName);
        File file = new File(filePath);
        if (file.isFile() && file.exists()) {
            try {
                InputStream in = new FileInputStream(filePath);
                byte[] filebyte = IOUtils.toByteArray(in);
                in.close();
                result = filebyte;
            } catch (IOException var10) {
                var10.printStackTrace();
            }
        } else {
            System.out.println("文件不存在");
        }

        return result;
    }


    private String GettqFilepath() {
        String tqFilepath = "";
        String os = System.getProperty("os.name").toLowerCase();
        if (os.contains("win")) {
            tqFilepath = dmgisConfig.getWinpath();
        } else if (os.contains("nix") || os.contains("nux") || os.contains("aix")) {
            tqFilepath = dmgisConfig.getLinuxpath();
        }
        return tqFilepath;
    }


    /**
     * 将风速风向数据存到本地文件中
     * @param tempFilePath  临时文件路径
     * @param listGridVo    风速风向数据
     * @return 格点文件路径
     * @throws ParseException
     */
    public String[] getWindGridData (String tempFilePath, List <NumericaVo> listGridVo) throws ParseException {
        if (listGridVo.size() % 2 != 0) {
            logger.error("listGridVo 必须包含偶数个元素,同时包含U风和V风的数据");
            throw new IllegalArgumentException("listGridVo 必须包含偶数个元素,同时包含U风和V风的数据");
        }
        String[] windFiles = new String[listGridVo.size()];
        fileUtil.mkDirs(tempFilePath);// 创建文件夹
        // 当格点文件数量达到1000时清除
        fileUtil.ClearTempFiles(tempFilePath, 1000);
        for (int i = 0; i < listGridVo.size(); i += 2) {
            NumericaVo gridU = listGridVo.get(i);
            NumericaVo gridV = listGridVo.get(i + 1);
            try {
                DateTime forecastTime = DateTime.parseDateTime(gridU.getDatechar()).AddHours(Integer.parseInt(gridU.getTimechar()));
                String nTimes = String.format("%03d", Integer.parseInt(gridU.getNtimes()));

                String uFileName = gridU.getType() + "." + forecastTime.toDateTimeString("yyyyMMddHH.") + nTimes;
                String vFileName = gridV.getType() + "." + forecastTime.toDateTimeString("yyyyMMddHH.") + nTimes;

                File uGridFile = Paths.get(tempFilePath, uFileName).toFile();
                File vGridFile = Paths.get(tempFilePath, vFileName).toFile();
                //判断文件是否存在
                Boolean filesExit = true;

                if (!uGridFile.exists() && !vGridFile.exists()) {
                    //检查mongodb是否存在该文件
                    byte[] data = gridU.getData();
                    if (data != null && data.length > 10) {
                        fileUtil.bytesToFile(data, uGridFile.getPath());
                        //处理v文件
                        byte[] data1 = gridV.getData();
                        if (data1 != null && data1.length > 0) {
                            fileUtil.bytesToFile(data1, vGridFile.getPath());//保存v文件
                        }
                    } else {
                        filesExit = false;//文件不存在
                    }
                }
                if (filesExit) {
                    windFiles[i] = uGridFile.getPath();
                    windFiles[i + 1] = vGridFile.getPath();
                } else {
                    windFiles[i] = windFiles[i + 1] = "";
                }
            } catch (Exception e) {
                logger.error("get Wind Grid Data error");
                throw new IllegalArgumentException("get Wind Grid Data error", e);
            }
        }
        return windFiles;
    }


    /**
     * 将格点数据存到本地文件中
     * @param tempFilePath 文件地址
     * @param listGridVo  格点数据
     * @return 格点文件路径
     * @throws ParseException
     */
    public String[] getGridData (String tempFilePath, List <NumericaVo> listGridVo) throws ParseException {
        if (listGridVo == null || listGridVo.isEmpty()) {
            return new String[0];
        }
        // 创建文件夹
        fileUtil.mkDirs(tempFilePath);
        // 当格点文件数量达到1000时清除
        fileUtil.ClearTempFiles(tempFilePath, 1000);
        String[] files = new String[listGridVo.size()];
        for (int i = 0; i < listGridVo.size(); i++) {
            NumericaVo gridVo = listGridVo.get(i);
            try {
                DateTime forecastTime = DateTime.parseDateTime(gridVo.getDatechar()).AddHours(Integer.parseInt(gridVo.getTimechar()));
                String ntimes = String.format("%03d", Integer.parseInt(gridVo.getNtimes()));
                String gridType = gridVo.getType();
                String fileName = gridType + "." + forecastTime.toDateTimeString("yyyyMMddHH.")
                        + ntimes;
                Path filePath = Paths.get(tempFilePath, fileName);
                File gridFile = filePath.toFile();
                if (!Files.exists(filePath)) {
                    byte[] data = gridVo.getData();
                    if (data != null && data.length > 10) {
                        fileUtil.bytesToFile(data, gridFile.getPath());
                        files[i] = filePath.toString();
                    } else {
                        files[i] = "";
                    }
                } else {
                    files[i] = filePath.toString();
                }
            } catch (Exception e) {
                logger.error("Error processing grid data at index {}: {}", i, e.getMessage(), e);
                files[i] = "";
            }
        }
        return files;
    }

}
